﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

namespace BPMS.Core
{
    /// <summary>
    /// SQL Server数据库类型映射
    /// http://msdn.microsoft.com/zh-cn/library/cc716729(v=vs.110).aspx
    /// </summary>
    public class DbTypeParser
    {
        private class TypeMapEntry
        {
            public Type ClrType;
            public DbType DbType;
            public SqlDbType SqlDbType;
            public string StrSqlType;

            public TypeMapEntry()
            {
                ClrType = typeof(object);
                DbType = DbType.Object;
                SqlDbType = SqlDbType.Variant;
                StrSqlType = "sql_variant";
            }

            public TypeMapEntry(string strSqlType, Type type, SqlDbType sqlDbType, DbType dbType)
            {
                this.StrSqlType = strSqlType;
                this.ClrType = type;
                this.DbType = dbType;
                this.SqlDbType = sqlDbType;
            }

        };

        static List<TypeMapEntry> dbTypeList = new List<TypeMapEntry>();

        static DbTypeParser()
        {
            dbTypeList = new List<TypeMapEntry>()
            {
                new TypeMapEntry("bigint",typeof(Int64),SqlDbType.BigInt,DbType.Int64),
                new TypeMapEntry("binary",typeof(byte[]),SqlDbType.VarBinary,DbType.Binary),
                new TypeMapEntry("bit",typeof(bool),SqlDbType.Bit,DbType.Boolean),
                new TypeMapEntry("char",typeof(string),SqlDbType.Char,DbType.AnsiStringFixedLength),
                new TypeMapEntry("date",typeof(DateTime),SqlDbType.Date,DbType.Date),
                new TypeMapEntry("datetime",typeof(DateTime),SqlDbType.DateTime,DbType.DateTime),
                new TypeMapEntry("datetime2",typeof(DateTime),SqlDbType.DateTime2,DbType.DateTime2),
                new TypeMapEntry("datetimeoffset",typeof(DateTimeOffset),SqlDbType.DateTimeOffset,DbType.DateTimeOffset),
                new TypeMapEntry("decimal",typeof(decimal),SqlDbType.Decimal,DbType.Decimal),
                new TypeMapEntry("varbinary(max)",typeof(byte[]),SqlDbType.VarBinary,DbType.Binary),
                new TypeMapEntry("float",typeof(double),SqlDbType.Float,DbType.Double),
                new TypeMapEntry("image",typeof(byte[]),SqlDbType.Binary,DbType.Binary),
                new TypeMapEntry("int",typeof(Int32),SqlDbType.Int,DbType.Int32),
                new TypeMapEntry("money",typeof(Decimal),SqlDbType.Money,DbType.Decimal),
                new TypeMapEntry("nchar",typeof(string),SqlDbType.NChar,DbType.StringFixedLength),
                new TypeMapEntry("ntext",typeof(string),SqlDbType.NText,DbType.String),
                new TypeMapEntry("numeric",typeof(decimal),SqlDbType.Decimal,DbType.Decimal),
                new TypeMapEntry("nvarchar",typeof(string),SqlDbType.NVarChar,DbType.String),
                new TypeMapEntry("real",typeof(Single),SqlDbType.Real,DbType.Single),
                new TypeMapEntry("rowversion",typeof(byte[]),SqlDbType.Timestamp,DbType.Binary),
                new TypeMapEntry("smalldatetime",typeof(DateTime),SqlDbType.DateTime,DbType.DateTime),
                new TypeMapEntry("smallint",typeof(Int16),SqlDbType.SmallInt,DbType.Int16),
                new TypeMapEntry("smallmoney",typeof(decimal),SqlDbType.SmallMoney,DbType.Decimal),
                new TypeMapEntry("sql_variant",typeof(object),SqlDbType.Variant,DbType.Object),
                new TypeMapEntry("text",typeof(string),SqlDbType.Text,DbType.String),
                new TypeMapEntry("time",typeof(TimeSpan),SqlDbType.Time,DbType.Time),
                new TypeMapEntry("timestamp",typeof(byte[]),SqlDbType.Timestamp,DbType.Binary),
                new TypeMapEntry("tinyint",typeof(byte),SqlDbType.TinyInt,DbType.Byte),
                new TypeMapEntry("uniqueidentifier",typeof(Guid),SqlDbType.UniqueIdentifier,DbType.Guid),
                new TypeMapEntry("varbinary",typeof(byte[]),SqlDbType.VarBinary,DbType.Binary),
                new TypeMapEntry("varchar",typeof(string),SqlDbType.VarChar,DbType.AnsiString),
                new TypeMapEntry("xml",typeof(string),SqlDbType.Xml,DbType.Xml)
            };
        }

        public static Type ToClrType(string sqlType)
        {
            TypeMapEntry mapEntry = FindMapEntry(sqlType);
            return mapEntry.ClrType;
        }

        public static DbType ToDbType(string sqlType)
        {
            TypeMapEntry mapEntry = FindMapEntry(sqlType);
            return mapEntry.DbType;
        }

        public static DbType ToDbType(Type clrType)
        {
            TypeMapEntry mapEntry = FindMapEntry(clrType);
            return mapEntry.DbType;
        }

        public static SqlDbType ToSqlDbType(string sqlType)
        {
            TypeMapEntry mapEntry = FindMapEntry(sqlType);
            return mapEntry.SqlDbType;
        }

        private static TypeMapEntry FindMapEntry(string sqlType)
        {
            TypeMapEntry mapEntry = dbTypeList.FirstOrDefault(map =>
              {
                  return string.Equals(map.StrSqlType, sqlType, StringComparison.OrdinalIgnoreCase);
              });
            return mapEntry ?? new TypeMapEntry();
        }
        private static TypeMapEntry FindMapEntry(Type clrType)
        {
            TypeMapEntry mapEntry = dbTypeList.FirstOrDefault(item =>
            {
                return item.ClrType.Equals(clrType);
            });
            return mapEntry ?? new TypeMapEntry();
        }
    }
}
